package org.funny.machine32.instructionset;

import com.google.common.base.Strings;
import org.funny.machine32.base.Instruction;
import org.funny.machine32.hardware.common.IExecution;
import org.funny.machine32.hardware.common.MachineState;
import org.funny.machine32.hardware.processors.cpu.ALU;
import org.funny.machine32.hardware.processors.cpu.CpuRegisterFile;
import org.funny.machine32.utils.BinUtils;
import org.funny.machine32.utils.StringUtils;

import java.io.File;
import java.io.FileNotFoundException;
import java.net.URL;
import java.util.Scanner;

public class InstructionsBuilder {
    private Instructions instructions;

    public Instructions getInstructions() {
        return instructions;
    }

    public InstructionsBuilder init() {
        System.out.println("Init instructions from instructions.txt");
        instructions = new Instructions();
        ClassLoader classLoader = InstructionsBuilder.class.getClassLoader();
        URL url = classLoader.getResource("instructions.txt");
        File file = new File(url.getFile());
        Scanner input;
        try {
            input = new Scanner(file);
        } catch (FileNotFoundException e) {
            e.printStackTrace();
            return null;
        }

        Instruction instruction = new Instruction();
        while (input.hasNext()) {
            String nextLine = input.nextLine();
            if (Strings.isNullOrEmpty(nextLine.trim())) {
                instructions.addInstruction(instruction);
                instruction = new Instruction();
            }
            if (nextLine.startsWith("example:")) {
                String example = StringUtils.substringAfter(nextLine, "example: ");
                instruction.setExample(example);
            }
            if (nextLine.startsWith("format:")) {
                String format = StringUtils.substringAfter(nextLine, "format: ");
                instruction.setFormat(format);
            }
            if (nextLine.startsWith("mask:")) {
                String mask = StringUtils.substringAfter(nextLine, "mask: ");
                instruction.setMask(mask);
            }
        }

        System.out.println("End init.");
        return this;
    }

    public InstructionsBuilder execution(String mnemonic, IExecution execution) {
        Instruction instruction = this.instructions.getCache().get(mnemonic);
        instruction.setExecution(execution);
        return this;
    }

    public Instructions build() {
        InstructionsBuilder builder = init();
        /**
         * 算术运算
         * */
        builder = builder.execution("add", new IExecution() {
            @Override
            public void execute(MachineState state, int[] operator) {
                CpuRegisterFile registerFile = state.getComponent(CpuRegisterFile.class);
                ALU alu = state.getComponent(ALU.class);

                int add1 = registerFile.getRegisterValue(operator[2]);
                int add2 = registerFile.getRegisterValue(operator[3]);
                int sum = alu.add(add1, add2);
                // overflow on A+B detected when A and B have same sign and A+B has other sign.
                if ((add1 >= 0 && add2 >= 0 && sum < 0) || (add1 < 0 && add2 < 0 && sum >= 0)) {
                    //throw new ProcessingException(statement, "arithmetic overflow", Exceptions.ARITHMETIC_OVERFLOW_EXCEPTION);
                }
                registerFile.updateRegister(operator[1], sum);
            }
        }).execution("addi", new IExecution() {
            @Override
            public void execute(MachineState state, int[] operator) {
                CpuRegisterFile registerFile = state.getComponent(CpuRegisterFile.class);
                ALU alu = state.getComponent(ALU.class);

                int add1 = registerFile.getRegisterValue(operator[2]);
                int add2 = operator[3] << 16 >> 16;
                int sum = alu.add(add1, add2);
                // overflow on A+B detected when A and B have same sign and A+B has other sign.
                if ((add1 >= 0 && add2 >= 0 && sum < 0)
                        || (add1 < 0 && add2 < 0 && sum >= 0)) {
                    //throw new ProcessingException(statement, "arithmetic overflow", Exceptions.ARITHMETIC_OVERFLOW_EXCEPTION);
                }
                registerFile.updateRegister(operator[1], sum);
            }
        }).execution("addiu", new IExecution() {
            @Override
            public void execute(MachineState state, int[] operator) {
                CpuRegisterFile registerFile = state.getComponent(CpuRegisterFile.class);
                ALU alu = state.getComponent(ALU.class);

                int add1 = registerFile.getRegisterValue(operator[2]);
                int add2 = operator[3] << 16 >> 16;
                int sum = alu.add(add1, add2);
                registerFile.updateRegister(operator[1], sum);
            }
        }).execution("addu", new IExecution() {
            @Override
            public void execute(MachineState state, int[] operator) {
                CpuRegisterFile registerFile = state.getComponent(CpuRegisterFile.class);
                ALU alu = state.getComponent(ALU.class);

                int add1 = registerFile.getRegisterValue(operator[2]);
                int add2 = registerFile.getRegisterValue(operator[3]);
                int sum = alu.add(add1, add2);
                registerFile.updateRegister(operator[1], sum);
            }
        }).execution("clo", new IExecution() {
            @Override
            public void execute(MachineState state, int[] operator) {
                CpuRegisterFile registerFile = state.getComponent(CpuRegisterFile.class);

                int value = registerFile.getRegisterValue(operator[2]);
                int leadingOnes = 0;
                int bitPosition = 31;
                while (BinUtils.bitValue(value, bitPosition) == 1 && bitPosition >= 0) {
                    leadingOnes++;
                    bitPosition--;
                }
                registerFile.updateRegister(operator[1], leadingOnes);
            }
        }).execution("clz", new IExecution() {
            @Override
            public void execute(MachineState state, int[] operator) {
                CpuRegisterFile registerFile = state.getComponent(CpuRegisterFile.class);

                int value = registerFile.getRegisterValue(operator[2]);
                int leadingZeros = 0;
                int bitPosition = 31;
                while (BinUtils.bitValue(value, bitPosition) == 0 && bitPosition >= 0) {
                    leadingZeros++;
                    bitPosition--;
                }
                registerFile.updateRegister(operator[1], leadingZeros);
            }
        }).execution("lui", new IExecution() {
            @Override
            public void execute(MachineState state, int[] operator) {
                CpuRegisterFile registerFile = state.getComponent(CpuRegisterFile.class);
                registerFile.updateRegister(operator[1], operator[2] << 16);
            }
        }).execution("sub", new IExecution() {
            @Override
            public void execute(MachineState state, int[] operator) {
                CpuRegisterFile registerFile = state.getComponent(CpuRegisterFile.class);
                ALU alu = state.getComponent(ALU.class);

                int sub1 = registerFile.getRegisterValue(operator[2]);
                int sub2 = registerFile.getRegisterValue(operator[3]);
                int dif = alu.sub(sub1, sub2);
                // overflow on A-B detected when A and B have opposite signs and A-B has B's sign
                if ((sub1 >= 0 && sub2 < 0 && dif < 0) || (sub1 < 0 && sub2 >= 0 && dif >= 0)) {
                    // throw new ProcessingException(statement, "arithmetic overflow", Exceptions.ARITHMETIC_OVERFLOW_EXCEPTION);
                }
                registerFile.updateRegister(operator[1], dif);
            }
        }).execution("subu", new IExecution() {
            @Override
            public void execute(MachineState state, int[] operator) {
                CpuRegisterFile registerFile = state.getComponent(CpuRegisterFile.class);
                ALU alu = state.getComponent(ALU.class);

                int sub1 = registerFile.getRegisterValue(operator[2]);
                int sub2 = registerFile.getRegisterValue(operator[3]);
                int dif = alu.sub(sub1, sub2);
                registerFile.updateRegister(operator[1], dif);
            }
        });

        /**
         * 移位运算
         * */
        builder = builder.execution("sll", new IExecution() {
            @Override
            public void execute(MachineState state, int[] operator) {
                CpuRegisterFile registerFile = state.getComponent(CpuRegisterFile.class);
                ALU alu = state.getComponent(ALU.class);

                int val1 = registerFile.getRegisterValue(operator[2]);
                int val2 = registerFile.getRegisterValue(operator[3]);
                int val = alu.shiftl(val1, val2);
                registerFile.updateRegister(operator[1], val);
            }
        }).execution("sllv", new IExecution() {
            @Override
            public void execute(MachineState state, int[] operator) {
                CpuRegisterFile registerFile = state.getComponent(CpuRegisterFile.class);
                ALU alu = state.getComponent(ALU.class);

                int val1 = registerFile.getRegisterValue(operator[2]);
                int val2 = registerFile.getRegisterValue(operator[3]);
                int val = alu.shiftl(val1, alu.and(val2, 0x0000001F));
                registerFile.updateRegister(operator[1], val);
            }
        }).execution("sra", new IExecution() {
            @Override
            public void execute(MachineState state, int[] operator) {
                CpuRegisterFile registerFile = state.getComponent(CpuRegisterFile.class);
                ALU alu = state.getComponent(ALU.class);

                int val1 = registerFile.getRegisterValue(operator[2]);
                int val2 = registerFile.getRegisterValue(operator[3]);
                int val = alu.shiftr(val1, val2);
                registerFile.updateRegister(operator[1], val);
            }
        }).execution("srav", new IExecution() {
            @Override
            public void execute(MachineState state, int[] operator) {
                CpuRegisterFile registerFile = state.getComponent(CpuRegisterFile.class);
                ALU alu = state.getComponent(ALU.class);

                int val1 = registerFile.getRegisterValue(operator[2]);
                int val2 = registerFile.getRegisterValue(operator[3]);
                int val = alu.shiftr(val1, alu.and(val2, 0x0000001F));
                registerFile.updateRegister(operator[1], val);
            }
        }).execution("srl", new IExecution() {
            @Override
            public void execute(MachineState state, int[] operator) {
                CpuRegisterFile registerFile = state.getComponent(CpuRegisterFile.class);
                ALU alu = state.getComponent(ALU.class);

                int val1 = registerFile.getRegisterValue(operator[2]);
                int val2 = registerFile.getRegisterValue(operator[3]);
                int val = alu.shiftru(val1, val2);
                registerFile.updateRegister(operator[1], val);
            }
        }).execution("srlv", new IExecution() {
            @Override
            public void execute(MachineState state, int[] operator) {
                CpuRegisterFile registerFile = state.getComponent(CpuRegisterFile.class);
                ALU alu = state.getComponent(ALU.class);

                int val1 = registerFile.getRegisterValue(operator[2]);
                int val2 = registerFile.getRegisterValue(operator[3]);
                int val = alu.shiftru(val1, alu.and(val2, 0x0000001F));
                registerFile.updateRegister(operator[1], val);
            }
        });

        /**
         * 逻辑运算
         * */
        builder = builder.execution("and", new IExecution() {
            @Override
            public void execute(MachineState state, int[] operator) {
                CpuRegisterFile registerFile = state.getComponent(CpuRegisterFile.class);
                ALU alu = state.getComponent(ALU.class);

                int val1 = registerFile.getRegisterValue(operator[2]);
                int val2 = registerFile.getRegisterValue(operator[3]);
                int val = alu.and(val1, val2);
                registerFile.updateRegister(operator[1], val);
            }
        }).execution("andi", new IExecution() {
            @Override
            public void execute(MachineState state, int[] operator) {
                CpuRegisterFile registerFile = state.getComponent(CpuRegisterFile.class);
                ALU alu = state.getComponent(ALU.class);

                int val1 = registerFile.getRegisterValue(operator[2]);
                int val = alu.and(val1, alu.and(operator[3], 0x0000FFFF));
                registerFile.updateRegister(operator[1], val);
            }
        }).execution("nop", new IExecution() {
            @Override
            public void execute(MachineState state, int[] operator) {
                //no operation
            }
        }).execution("nor", new IExecution() {
            @Override
            public void execute(MachineState state, int[] operator) {
                CpuRegisterFile registerFile = state.getComponent(CpuRegisterFile.class);
                ALU alu = state.getComponent(ALU.class);

                int val1 = registerFile.getRegisterValue(operator[2]);
                int val2 = registerFile.getRegisterValue(operator[3]);
                int val = alu.nor(val1, val2);
                registerFile.updateRegister(operator[1], val);
            }
        }).execution("or", new IExecution() {
            @Override
            public void execute(MachineState state, int[] operator) {
                CpuRegisterFile registerFile = state.getComponent(CpuRegisterFile.class);
                ALU alu = state.getComponent(ALU.class);

                int val1 = registerFile.getRegisterValue(operator[2]);
                int val2 = registerFile.getRegisterValue(operator[3]);
                int val = alu.or(val1, val2);
                registerFile.updateRegister(operator[1], val);
            }
        }).execution("ori", new IExecution() {
            @Override
            public void execute(MachineState state, int[] operator) {
                CpuRegisterFile registerFile = state.getComponent(CpuRegisterFile.class);
                ALU alu = state.getComponent(ALU.class);

                int val1 = registerFile.getRegisterValue(operator[2]);
                int val = alu.or(val1, alu.and(operator[3], 0x0000FFFF));
                registerFile.updateRegister(operator[1], val);
            }
        }).execution("xor", new IExecution() {
            @Override
            public void execute(MachineState state, int[] operator) {
                CpuRegisterFile registerFile = state.getComponent(CpuRegisterFile.class);
                ALU alu = state.getComponent(ALU.class);

                int val1 = registerFile.getRegisterValue(operator[2]);
                int val2 = registerFile.getRegisterValue(operator[3]);
                int val = alu.xor(val1, val2);
                registerFile.updateRegister(operator[1], val);
            }
        }).execution("xori", new IExecution() {
            @Override
            public void execute(MachineState state, int[] operator) {
                CpuRegisterFile registerFile = state.getComponent(CpuRegisterFile.class);
                ALU alu = state.getComponent(ALU.class);

                int val1 = registerFile.getRegisterValue(operator[2]);
                int val = alu.xor(val1, alu.and(operator[3], 0x0000FFFF));
                registerFile.updateRegister(operator[1], val);
            }
        });

        /**
         * 条件测试或转移
         * */
        builder = builder.execution("movn", new IExecution() {
            @Override
            public void execute(MachineState state, int[] operator) {
                CpuRegisterFile registerFile = state.getComponent(CpuRegisterFile.class);
                if (registerFile.getRegisterValue(operator[3]) != 0) {
                    registerFile.updateRegister(operator[1], registerFile.getRegisterValue(operator[2]));
                }
            }
        }).execution("movz", new IExecution() {
            @Override
            public void execute(MachineState state, int[] operator) {
                CpuRegisterFile registerFile = state.getComponent(CpuRegisterFile.class);
                if (registerFile.getRegisterValue(operator[3]) == 0) {
                    registerFile.updateRegister(operator[1], registerFile.getRegisterValue(operator[2]));
                }
            }
        }).execution("slt", new IExecution() {
            @Override
            public void execute(MachineState state, int[] operator) {
                CpuRegisterFile registerFile = state.getComponent(CpuRegisterFile.class);

                int val1 = registerFile.getRegisterValue(operator[2]);
                int val2 = registerFile.getRegisterValue(operator[3]);
                registerFile.updateRegister(operator[1], (val1 < val2) ? 1 : 0);
            }
        }).execution("slti", new IExecution() {
            @Override
            public void execute(MachineState state, int[] operator) {
                CpuRegisterFile registerFile = state.getComponent(CpuRegisterFile.class);

                int val1 = registerFile.getRegisterValue(operator[2]);
                registerFile.updateRegister(operator[1], (val1 < (operator[3] << 16 >> 16)) ? 1 : 0);
            }
        }).execution("sltiu", new IExecution() {
            @Override
            public void execute(MachineState state, int[] operator) {
                CpuRegisterFile registerFile = state.getComponent(CpuRegisterFile.class);

                int first = registerFile.getRegisterValue(operator[2]);
                int second = operator[3] << 16 >> 16;
                if (first >= 0 && second >= 0 || first < 0 && second < 0) {
                    registerFile.updateRegister(operator[1], (first < second) ? 1 : 0);
                } else {
                    registerFile.updateRegister(operator[1], (first >= 0) ? 1 : 0);
                }
            }
        }).execution("sltu", new IExecution() {
            @Override
            public void execute(MachineState state, int[] operator) {
                CpuRegisterFile registerFile = state.getComponent(CpuRegisterFile.class);

                int first = registerFile.getRegisterValue(operator[2]);
                int second = registerFile.getRegisterValue(operator[3]);
                if (first >= 0 && second >= 0 || first < 0 && second < 0) {
                    registerFile.updateRegister(operator[1], (first < second) ? 1 : 0);
                } else {
                    registerFile.updateRegister(operator[1], (first >= 0) ? 1 : 0);
                }
            }
        });

        /**
         * 乘除运算
         * */
        builder = builder.execution("div", new IExecution() {
            @Override
            public void execute(MachineState state, int[] operator) {
                CpuRegisterFile registerFile = state.getComponent(CpuRegisterFile.class);

                int val1 = registerFile.getRegisterValue(operator[1]);
                int val2 = registerFile.getRegisterValue(operator[2]);
                if (val1 == 0) {
                    // Note: no base and undefined results for zero div
                    // COD3 Appendix A says "with overflow" but MIPS 32 instruction set
                    // specification says "no arithmetic exception under any circumstances".
                    return;
                }
                // Register 33 is HIGH and 34 is LOW
                registerFile.getHi().write(val1 % val2);
                registerFile.getLo().write(val1 / val2);
            }
        }).execution("divu", new IExecution() {
            @Override
            public void execute(MachineState state, int[] operator) {
                CpuRegisterFile registerFile = state.getComponent(CpuRegisterFile.class);

                int val1 = registerFile.getRegisterValue(operator[1]);
                int val2 = registerFile.getRegisterValue(operator[2]);
                if (val1 == 0) {
                    // Note: no base, and undefined results for zero divide
                    return;
                }
                long oper1 = ((long) val1) << 32 >>> 32;
                long oper2 = ((long) val2) << 32 >>> 32;
                // Register 33 is HIGH and 34 is LOW
                registerFile.getHi().write((int) (((oper1 % oper2) << 32) >> 32));
                registerFile.getLo().write((int) (((oper1 / oper2) << 32) >> 32));
            }
        }).execution("madd", new IExecution() {
            @Override
            public void execute(MachineState state, int[] operator) {
                CpuRegisterFile registerFile = state.getComponent(CpuRegisterFile.class);

                int val1 = registerFile.getRegisterValue(operator[1]);
                int val2 = registerFile.getRegisterValue(operator[2]);
                long product = (long) val1 * (long) val2;
                // Register 33 is HIGH and 34 is LOW.
                long contentsHiLo = BinUtils.twoIntsToLong(registerFile.getHi().read(), registerFile.getLo().read());
                long sum = contentsHiLo + product;
                registerFile.getHi().write(BinUtils.highOrderLongToInt(sum));
                registerFile.getLo().write(BinUtils.lowOrderLongToInt(sum));
            }
        }).execution("maddu", new IExecution() {
            @Override
            public void execute(MachineState state, int[] operator) {
                CpuRegisterFile registerFile = state.getComponent(CpuRegisterFile.class);
                long val1 = ((long) registerFile.getRegisterValue(operator[1]) << 32 >>> 32);
                long val2 = ((long) registerFile.getRegisterValue(operator[2]) << 32 >>> 32);
                long product = val1 * val2;
                // Register 33 is HIGH and 34 is LOW.
                long contentsHiLo = BinUtils.twoIntsToLong(registerFile.getHi().read(), registerFile.getLo().read());
                long sum = contentsHiLo + product;
                registerFile.getHi().write(BinUtils.highOrderLongToInt(sum));
                registerFile.getLo().write(BinUtils.lowOrderLongToInt(sum));
            }
        }).execution("msub", new IExecution() {
            @Override
            public void execute(MachineState state, int[] operator) {
                CpuRegisterFile registerFile = state.getComponent(CpuRegisterFile.class);

                int val1 = registerFile.getRegisterValue(operator[1]);
                int val2 = registerFile.getRegisterValue(operator[2]);
                long product = (long) val1 * (long) val2;
                // Register 33 is HIGH and 34 is LOW.
                long contentsHiLo = BinUtils.twoIntsToLong(registerFile.getHi().read(), registerFile.getLo().read());
                long diff = contentsHiLo - product;
                registerFile.getHi().write(BinUtils.highOrderLongToInt(diff));
                registerFile.getLo().write(BinUtils.lowOrderLongToInt(diff));
            }
        }).execution("msubu", new IExecution() {
            @Override
            public void execute(MachineState state, int[] operator) {
                CpuRegisterFile registerFile = state.getComponent(CpuRegisterFile.class);
                long val1 = ((long) registerFile.getRegisterValue(operator[1]) << 32 >>> 32);
                long val2 = ((long) registerFile.getRegisterValue(operator[2]) << 32 >>> 32);
                long product = val1 * val2;
                // Register 33 is HIGH and 34 is LOW.
                long contentsHiLo = BinUtils.twoIntsToLong(registerFile.getHi().read(), registerFile.getLo().read());
                long diff = contentsHiLo - product;
                registerFile.getHi().write(BinUtils.highOrderLongToInt(diff));
                registerFile.getLo().write(BinUtils.lowOrderLongToInt(diff));
            }
        }).execution("mul", new IExecution() {
            @Override
            public void execute(MachineState state, int[] operator) {
                CpuRegisterFile registerFile = state.getComponent(CpuRegisterFile.class);

                int val1 = registerFile.getRegisterValue(operator[2]);
                int val2 = registerFile.getRegisterValue(operator[3]);
                long product = (long) val1 * (long) val2;
                registerFile.updateRegister(operator[1], (int) ((product << 32) >> 32));
                // Register 33 is HIGH and 34 is LOW.  Not required by MIPS; SPIM does it.
                registerFile.getHi().write((int) (product >> 32));
                registerFile.getLo().write((int) ((product << 32) >> 32));
            }
        }).execution("mult", new IExecution() {
            @Override
            public void execute(MachineState state, int[] operator) {
                CpuRegisterFile registerFile = state.getComponent(CpuRegisterFile.class);

                int val1 = registerFile.getRegisterValue(operator[1]);
                int val2 = registerFile.getRegisterValue(operator[2]);
                long product = (long) val1 * (long) val2;
                // Register 33 is HIGH and 34 is LOW
                registerFile.getHi().write((int) (product >> 32));
                registerFile.getLo().write((int) ((product << 32) >> 32));
            }
        }).execution("multu", new IExecution() {
            @Override
            public void execute(MachineState state, int[] operator) {
                CpuRegisterFile registerFile = state.getComponent(CpuRegisterFile.class);

                long val1 = ((long) registerFile.getRegisterValue(operator[1])) << 32 >>> 32;
                long val2 = ((long) registerFile.getRegisterValue(operator[2])) << 32 >>> 32;
                long product = val1 * val2;
                // Register 33 is HIGH and 34 is LOW
                registerFile.getHi().write((int) (product >> 32));
                registerFile.getLo().write((int) ((product << 32) >> 32));

            }
        });

        /**
         * 累加器存取
         * */
        builder = builder.execution("mfhi", new IExecution() {
            @Override
            public void execute(MachineState state, int[] operator) {
                CpuRegisterFile registerFile = state.getComponent(CpuRegisterFile.class);
                registerFile.updateRegister(operator[1], registerFile.getHi().read());
            }
        }).execution("mflo", new IExecution() {
            @Override
            public void execute(MachineState state, int[] operator) {
                CpuRegisterFile registerFile = state.getComponent(CpuRegisterFile.class);
                registerFile.updateRegister(operator[1], registerFile.getLo().read());
            }
        }).execution("mthi", new IExecution() {
            @Override
            public void execute(MachineState state, int[] operator) {
                CpuRegisterFile registerFile = state.getComponent(CpuRegisterFile.class);
                registerFile.getHi().write(registerFile.getRegisterValue(operator[1]));
            }
        }).execution("mtlo", new IExecution() {
            @Override
            public void execute(MachineState state, int[] operator) {
                CpuRegisterFile registerFile = state.getComponent(CpuRegisterFile.class);
                registerFile.getLo().write(registerFile.getRegisterValue(operator[1]));
            }
        });

        /**
         * 分支跳转
         * */
        builder = builder.execution("beq", new IExecution() {
            @Override
            public void execute(MachineState state, int[] operator) {
                CpuRegisterFile registerFile = state.getComponent(CpuRegisterFile.class);
                if (registerFile.getRegisterValue(operator[1]) == registerFile.getRegisterValue(operator[2])) {
                    int pc = registerFile.getPc().read() + (operator[3] << 2);
                    registerFile.getPc().write(pc);
                }
            }
        }).execution("bgez", new IExecution() {
            @Override
            public void execute(MachineState state, int[] operator) {
                CpuRegisterFile registerFile = state.getComponent(CpuRegisterFile.class);
                if (registerFile.getRegisterValue(operator[1]) >= 0) {
                    int pc = registerFile.getPc().read() + (operator[2] << 2);
                    registerFile.getPc().write(pc);
                }
            }
        }).execution("bgezal", new IExecution() {
            @Override
            public void execute(MachineState state, int[] operator) {
                CpuRegisterFile registerFile = state.getComponent(CpuRegisterFile.class);
                if (registerFile.getRegisterValue(operator[1]) >= 0) {
                    registerFile.updateRegister(31, registerFile.getPc().read());
                    int pc = registerFile.getPc().read() + (operator[2] << 2);
                    registerFile.getPc().write(pc);
                }
            }
        }).execution("bgtz", new IExecution() {
            @Override
            public void execute(MachineState state, int[] operator) {
                CpuRegisterFile registerFile = state.getComponent(CpuRegisterFile.class);
                if (registerFile.getRegisterValue(operator[1]) > 0) {
                    int pc = registerFile.getPc().read() + (operator[2] << 2);
                    registerFile.getPc().write(pc);
                }
            }
        }).execution("blez", new IExecution() {
            @Override
            public void execute(MachineState state, int[] operator) {
                CpuRegisterFile registerFile = state.getComponent(CpuRegisterFile.class);
                if (registerFile.getRegisterValue(operator[1]) <= 0) {
                    int pc = registerFile.getPc().read() + (operator[2] << 2);
                    registerFile.getPc().write(pc);
                }
            }
        }).execution("bltz", new IExecution() {
            @Override
            public void execute(MachineState state, int[] operator) {
                CpuRegisterFile registerFile = state.getComponent(CpuRegisterFile.class);
                if (registerFile.getRegisterValue(operator[1]) < 0) {
                    int pc = registerFile.getPc().read() + (operator[2] << 2);
                    registerFile.getPc().write(pc);
                }
            }
        }).execution("bltzal", new IExecution() {
            @Override
            public void execute(MachineState state, int[] operator) {
                CpuRegisterFile registerFile = state.getComponent(CpuRegisterFile.class);
                if (registerFile.getRegisterValue(operator[1]) < 0) {
                    registerFile.updateRegister(31, registerFile.getPc().read());
                    int pc = registerFile.getPc().read() + (operator[2] << 2);
                    registerFile.getPc().write(pc);
                }
            }
        }).execution("bne", new IExecution() {
            @Override
            public void execute(MachineState state, int[] operator) {
                CpuRegisterFile registerFile = state.getComponent(CpuRegisterFile.class);
                if (registerFile.getRegisterValue(operator[1]) != registerFile.getRegisterValue(operator[2])) {
                    int pc = registerFile.getPc().read() + (operator[3] << 2);
                    registerFile.getPc().write(pc);
                }
            }
        }).execution("j", new IExecution() {
            @Override
            public void execute(MachineState state, int[] operator) {
                CpuRegisterFile registerFile = state.getComponent(CpuRegisterFile.class);
                int address = (registerFile.getPc().read() & 0xF0000000 | (operator[1] << 2));
                registerFile.getPc().write(address);
            }
        }).execution("jal", new IExecution() {
            @Override
            public void execute(MachineState state, int[] operator) {
                CpuRegisterFile registerFile = state.getComponent(CpuRegisterFile.class);
                registerFile.updateRegister(31, registerFile.getPc().read());
                int address = (registerFile.getPc().read() & 0xF0000000 | (operator[1] << 2));
                registerFile.getPc().write(address);
            }
        }).execution("jalr", new IExecution() {
            @Override
            public void execute(MachineState state, int[] operator) {
                ;//jalr $t1,$t2
                //jalr $t1
            }
        }).execution("jr", new IExecution() {
            @Override
            public void execute(MachineState state, int[] operator) {
                CpuRegisterFile registerFile = state.getComponent(CpuRegisterFile.class);
                registerFile.getPc().write(registerFile.getRegisterValue(operator[1]));
            }
        });

        /**
         * 加载保存
         * */
        builder = builder.execution("lb", new IExecution() {
            @Override
            public void execute(MachineState state, int[] operator) {
                ;
            }
        }).execution("lbu", new IExecution() {
            @Override
            public void execute(MachineState state, int[] operator) {
                ;
            }
        }).execution("lh", new IExecution() {
            @Override
            public void execute(MachineState state, int[] operator) {
                ;
            }
        }).execution("lhu", new IExecution() {
            @Override
            public void execute(MachineState state, int[] operator) {
                ;
            }
        }).execution("lw", new IExecution() {
            @Override
            public void execute(MachineState state, int[] operator) {
                ;
            }
        }).execution("lwl", new IExecution() {
            @Override
            public void execute(MachineState state, int[] operator) {
                ;
            }
        }).execution("lwr", new IExecution() {
            @Override
            public void execute(MachineState state, int[] operator) {
                ;
            }
        }).execution("sb", new IExecution() {
            @Override
            public void execute(MachineState state, int[] operator) {
                ;
            }
        }).execution("sh", new IExecution() {
            @Override
            public void execute(MachineState state, int[] operator) {
                ;
            }
        }).execution("sw", new IExecution() {
            @Override
            public void execute(MachineState state, int[] operator) {
                ;
            }
        }).execution("swl", new IExecution() {
            @Override
            public void execute(MachineState state, int[] operator) {
                ;
            }
        }).execution("swr", new IExecution() {
            @Override
            public void execute(MachineState state, int[] operator) {
                ;
            }
        });

        /**
         * 读-修改-写
         * */
        builder = builder.execution("ll", new IExecution() {
            @Override
            public void execute(MachineState state, int[] operator) {
                ;
            }
        }).execution("sc", new IExecution() {
            @Override
            public void execute(MachineState state, int[] operator) {
                ;
            }
        });

        /**
         * 协处理器0
         * */
        /*
        builder = builder.execution("mfc0", new IExecution() {
            @Override
            public void execute(MachineState state, int[] operator) {
                CpuRegisterFile registerFile = state.getComponent(CpuRegisterFile.class);
                IntpRegisterFile intpRegisterFile = state.getComponent(IntpRegisterFile.class);
                registerFile.updateRegister(operator[1], intpRegisterFile.getRegisterValue(operator[2]));
            }
        }).execution("mtc0", new IExecution() {
            @Override
            public void execute(MachineState state, int[] operator) {
                CpuRegisterFile registerFile = state.getComponent(CpuRegisterFile.class);
                IntpRegisterFile intpRegisterFile = state.getComponent(IntpRegisterFile.class);
                intpRegisterFile.updateRegister(operator[2], registerFile.getRegisterValue(operator[1]));
            }
        }).execution("eret", new IExecution() {
            @Override
            public void execute(MachineState state, int[] operator) {
                // set EXL bit (bit 1) in Status register to 0 and set PC to EPC
                CpuRegisterFile registerFile = state.getComponent(CpuRegisterFile.class);
                IntpRegisterFile intpRegisterFile = state.getComponent(IntpRegisterFile.class);
                int value = BinUtils.clearBit(intpRegisterFile.getStatusRegister().read(), IntpRegisterFile.EXCEPTION_LEVEL);
                intpRegisterFile.getStatusRegister().write(value);
                registerFile.getPc().write(intpRegisterFile.getEpcRegister().read());
            }
        });
        */

        /**
         * 协处理器1
         * */
        builder = builder.execution("movf", new IExecution() {
            @Override
            public void execute(MachineState state, int[] operator) {
                ;
            }
        }).execution("movt", new IExecution() {
            @Override
            public void execute(MachineState state, int[] operator) {
                ;
            }
        });

        return builder.getInstructions();
    }
}
